//---------------[CSE420]----------[Project #4]----------[Part #3]---------------
#include <stdio.h>
#include <string.h>
#include <spu_mfcio.h>
#include "common.h"


//------------------------------[Global Variables]-------------------------------
int matrixA_row_InSPE[NUM_OF_COLS]  QWORD_ALIGNED;
int matrixB_col_InSPE[NUM_OF_ROWS]  QWORD_ALIGNED;
int sum                             QWORD_ALIGNED;

const int dt_unit = 4096;
CONTROL_BLOCK cb QWORD_ALIGNED;


//----------------------------[Forward Declarations]-----------------------------
void readControlBlock(uint64_t *argp);
void readMatrixRow   (int *spuptr, int *ppuptr);
void readMatrixCol   (int *spuptr, int *ppuptr);


//------------------------------------[Main]-------------------------------------
int main(uint64_t speid, uint64_t argp, uint64_t envp)
{
	/* Read input data */
	readControlBlock(&argp);
	readMatrixRow   (&matrixA_row_InSPE[0], cb.matrixA_row);
	readMatrixCol   (&matrixB_col_InSPE[0], cb.matrixB_col);

	/* Multiply single row by single column */
	for(int i = 0; i < NUM_OF_ROWS; i++)
	{
		sum += matrixA_row_InSPE[i] * matrixB_col_InSPE[i];
	}

	/* Write output data */
	mfc_put(&sum, cb.SPU_result, sizeof(int), 2, 0, 0);
	mfc_write_tag_mask(1 << 2);
	mfc_read_tag_status_all();

}


//---------------------------------[Functions]-----------------------------------
/* Reads control block data from PPE */
void readControlBlock(uint64_t *argp)
{
	mfc_get(&cb, *argp, sizeof(cb), 0, 0, 0);
	mfc_write_tag_mask(1 << 0);
	mfc_read_tag_status_all();
}

/* Reads data block from PPE */
void readMatrixRow(int *spuptr, int *ppuptr)
{
	int *spulast = spuptr + NUM_OF_COLS;

	while ( spuptr < spulast )
	{
		int nwords = ( spuptr + dt_unit > spulast ) ? (spulast - spuptr) : dt_unit;

		mfc_get(spuptr, ppuptr, 4 * nwords, 0, 0, 0);
		mfc_write_tag_mask(1 << 0);
		mfc_read_tag_status_all();
		spuptr += dt_unit;
		ppuptr += dt_unit;
	}
}

/* Reads data block from PPE */
void readMatrixCol(int *spuptr, int *ppuptr)
{
	int *spulast = spuptr + NUM_OF_ROWS;

	while ( spuptr < spulast )
	{
		int nwords = ( spuptr + dt_unit > spulast ) ? (spulast - spuptr) : dt_unit;

		mfc_get(spuptr, ppuptr, 4 * nwords, 0, 0, 0);
		mfc_write_tag_mask(1 << 0);
		mfc_read_tag_status_all();
		spuptr += dt_unit;
		ppuptr += dt_unit;
	}
}
//------------------------------------[END]--------------------------------------
